package com.lkm.market2_0.m_imple.steelyardserver.server;

import android.os.Handler;
import android.os.SystemClock;

import com.lkm.frame.P;
import com.lkm.frame.task2.ITaskExecutor;
import com.lkm.frame.task2.Task;
import com.lkm.frame.task2.TaskAdapter;
import com.lkm.frame.task2.TaskManager;
import com.lkm.hardware_connect.IHardwareControler;
import com.lkm.javatool.FlowStepRuner;
import com.lkm.javatool.NumberHelp;
import com.lkm.javatool.lang.RunnablePR;
import com.lkm.market2_0.help.UIP;

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;



public abstract class AbsSendWriteTask extends TaskAdapter<Object[], Void, Boolean> {

    private FlowStepRuner sendTitleFlowStepRuner;
    private IHardwareControler mBluetoothSocket;

    protected ReceiveTask mReceiveTask;

    protected volatile long lastActionTime;
    

    public AbsSendWriteTask(ITaskExecutor<Object[], Void, Boolean> taskExecutor, String id, TaskManager mTaskManager, IHardwareControler bluetoothSocket, ReceiveTask mReceiveTask) {
        super(taskExecutor, id, mTaskManager);
        mBluetoothSocket = bluetoothSocket;

        sendTitleFlowStepRuner = new FlowStepRuner.Build()

                .addRun("SentRequestRunnable", new SentRequestRunnable())
                .addRun("SendContentRunnable", new SendContentRunnable())
                .build();

        this.mReceiveTask=mReceiveTask;
        isNio = mReceiveTask.isNio();
    }

    
    private Handler mHandler;
    @Override
    public void onPreExecute() {
        super.onPreExecute();
        
        
        writeOutTime();
    }

    private void writeOutTime(){
        
        if(configWriteOutTime()>0) {
            if(!getIsContinue())return;

            if (mHandler == null)
                mHandler = new Handler();

            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if(!getIsContinue())return;

                    boolean isCancel = false;

                        //超时了 mReceiveTask.statusInfo.getLastActionTime()
                        if(SystemClock.uptimeMillis() - lastActionTime >= configWriteOutTime()){
                            
                            if(onWriteOutTime()){
                                isCancel = false;
                            }else {
                                isCancel = true;
                            }
                        }else{
                            isCancel = false;
                            
                            writeOutTime();

                        }


                    if(isCancel)
                    cancel();
                }
            }, configWriteOutTime()/2);
        }

    }

    

    protected int configWriteOutTime(){
        return Config.writeOutTime;
    }

    

    protected boolean onWriteOutTime(){
        return false;
    }

    

    protected boolean configIsWatiTick(){
        return true;
    }


    @Override
    public void onFinish(Boolean aBoolean) {
        super.onFinish(aBoolean);
        if(mHandler!=null)
        mHandler.removeCallbacksAndMessages(null);
    }

    @Override
    public void onCancel() {
        super.onCancel();
        if(mHandler!=null)
        mHandler.removeCallbacksAndMessages(null);
    }

    

    
    

    protected void onPreData(){}


    

    protected  byte[] onGetRequestCMDContent(){
        return null;
    }

    

    protected abstract byte onGetRequestCMD(int[] outDataSize);

    


    private boolean isNio;


    
    private class SentRequestRunnable implements Runnable {
        @Override
        public void run() {
            if(isNio){
                sentRequest();
            }else
            mTaskExecutor.executor(new RunnablePR<Object[], Void>() {
                @Override
                public Void run(Object[] param) {
                    return sentRequest();
                }
            }, getParam());
        }
    }
    private Void sentRequest(){
                    onPreData();
                    byte[] data = new byte[]{0x55, (byte) 0xAA, 0x26, 0x06, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x0D};

                    
                    byte checkNum=0;
                    byte[] dataContent= onGetRequestCMDContent();
                    if(dataContent!=null)
                    for(int i=0;i<dataContent.length;i++){
                        data[i+6]=dataContent[i];
                        checkNum+=dataContent[i];
                    }


                    int[] outDataSize = new int[1];
                    data[3] = (byte) onGetRequestCMD(outDataSize);

                    
                    
                    byte[] dataSizeBytes = NumberHelp.intToBytesDesc(outDataSize[0]);
                    data[4] = dataSizeBytes[2];
                    data[5] = dataSizeBytes[3];

                    checkNum+=(data[4] + data[5] + data[3]);
                    data[data.length - 2] = checkNum;

                    int writeSize = -1;
                    try {

                        writeSize = mBluetoothSocket.write(data);
                        if (P.isDebug()) {
                            StringBuilder stringBuilder=new StringBuilder();
                            for(byte b:data){
                                stringBuilder.append(" ");
                                stringBuilder.append(NumberHelp.bytesToHex(b));
                            }
                            String log="======发送："+writeSize+"   "+stringBuilder.toString();
                           // P.p(log);
                            if(UIP.isPrint()) {
                                UIP.p(log, "");
                            }
                        }
                    } catch (Exception e) {
                        writeSize = -1;
                    }
                    if (writeSize == -1) {
                        
                        complete(false);
                    } else {

                        lastActionTime = SystemClock.uptimeMillis();
                        
                        if(!configIsWatiTick()) {

                            sendTitleFlowStepRuner.runNext();
                        }
                    }

                    return null;

    }










    private AtomicBoolean isWaitWriteTick=new AtomicBoolean(true);


    

    protected boolean checkTickIsMe(CMDEntity cmdEntity){
        return true;
    }
    @Override
    public void orderCmd(int cmd, Object data) {
        super.orderCmd(cmd, data);
        if (data instanceof CMDEntity) {
            lastActionTime = SystemClock.uptimeMillis();
            CMDEntity cmdEntity = ((CMDEntity) data);

            

            if(!cmdEntity.isTickCMD())return;

            if(!checkTickIsMe(cmdEntity)){
                return;
            }

            if (cmdEntity.isTickOK()) {
                
                if (sendReentrantLock != null&&sendCondition!=null) {
                    if(isNio){
                        sendData.send();
                    }else{

                    
                    

                    sendReentrantLock.lock();
                    isReSendLast=false;
                    sendCondition.signal();
                    





                    sendReentrantLock.unlock();
                    }
                } else {

                    
                    if (isWaitWriteTick.get()) {
                        

                        isWaitWriteTick.set(false);

                        sendTitleFlowStepRuner.runNext();
                    }else {
                        
                        
                        complete(true);
                    }
                }
            } else {
                
                if (cmdEntity.isTickFail()&& sendReentrantLock != null) {
                   tryReSendLast();
                }else {
                    
                    complete(false);
                }
            }

        }
    }

    

    protected boolean tryReSendLast(){
        if(sendReentrantLock!=null){
            if(isNio){
                sendData.send();
            }else
            {
            sendReentrantLock.lock();
            isReSendLast = true;
            sendCondition.signal();
            sendReentrantLock.unlock();
            }
            return true;
        }
        return false;
    }

    

    protected abstract byte[] onGetSendDataItem(int index);




    
    volatile ReentrantLock sendReentrantLock;
    volatile Condition sendCondition;

    volatile boolean isReSendLast = false;
    

    private class SendContentRunnable implements Runnable {
        @Override
        public void run() {

            if(isNio){
                sendData.reset();
                
                synchronized (this) {
                    sendReentrantLock = new ReentrantLock();
                    sendCondition = sendReentrantLock.newCondition();
                }

                sendData.send();
            }else
            mTaskExecutor.executor(new RunnablePR<Object[], Void>() {
                @Override
                public Void run(Object[] param) {

                    
                    synchronized (this) {
                        sendReentrantLock = new ReentrantLock();
                        sendCondition = sendReentrantLock.newCondition();
                    }

                    sendData.reset();
                    while (getIsContinue()) {

                        try {
                            sendReentrantLock.lock();

                            if(sendData.send()){
                                break;
                            }
                            
                            if(getIsContinue()){
                                
                                sendCondition.await();
                            }

                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } finally {
                            try {
                                sendReentrantLock.unlock();
                            }catch (Exception e){}
                        }
                    }


                    return null;
                }
            }, getParam());
        }
    }

    private SendData sendData = new SendData();
    private class SendData{
        int i = -1;

        public void reset(){
            i = -1;
        }
        

        public boolean send(){
            i++;

            if(isReSendLast){
                i = i>0 ? (i-1) : 0;
            }

            byte[] data = onGetSendDataItem(i);
            if (data == null){
                
                complete(true);
                return true;
            }
            int writeSize = -1;
            try {

                writeSize = mBluetoothSocket.write(data);

                if (P.isDebug()) {
                    StringBuilder stringBuilder=new StringBuilder();
                    for(byte b:data){
                        stringBuilder.append(" ");
                        stringBuilder.append(NumberHelp.bytesToHex(b));
                    }
                   // P.p("======发送：第"+i+" "+writeSize+"   "+stringBuilder.toString());
                }
            } catch (Exception e) {
                writeSize = -1;
            }
            if (writeSize == -1) {
                
                complete(false);
            }
            return false;
        }

    }

    @Override
    public void doExecuting(Object[] param) {
        super.doExecuting(param);
        mReceiveTask.requertWriteTask(this);
    }

    

    public void send(){
        if (mBluetoothSocket == null) {
            complete(false);
            return;
        }
        
        sendTitleFlowStepRuner.runStep("WaitResponseRunnable");
        
        sendTitleFlowStepRuner.runStep("SentRequestRunnable");

    }

    


    public static String holdCharWidth32(String strName) {
        return holdCharWidth(32,strName);

    }
    public static String holdCharWidth(int holdW,String strName) {
        strName = holdCharWidthEven(strName);

        int w = getCharWidth(strName);
        int s = (holdW - w) / 2;
        StringBuilder sb = new StringBuilder(strName);
        for (int i = 0; i < s; i++) {
            sb.append("；");
        }
        return sb.toString();

    }

    

    public static String holdCharWidthEven(String strName) {
        int w = getCharWidth(strName);
        String result = strName;
        if (w % 2 != 0) {
            
            char[] ch = strName.toCharArray();
            for (int i = 0; i < ch.length; i++) {
                char c = ch[i];
                if (!isChinese(c)) {
                    String p = strName.substring(0, i);
                    String l = strName.substring(i);
                    result = p + " " + l;

                    break;
                }
            }

        }

        return result;
    }

    

    public static int getCharWidth(String strName) {
        int charWidth = 0;
        char[] ch = strName.toCharArray();
        for (int i = 0; i < ch.length; i++) {
            char c = ch[i];
            if (isChinese(c)) {
                charWidth += 2;
            } else {
                charWidth += 1;
            }
        }
        return charWidth;
    }


    
    private static boolean isChinese(char c) {
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
        if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
                || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS
                || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION) {
            return true;
        }
        return false;
    }




    private String getSpaceChars(int num) {
        String sc = "";
        for (int i = 0; i < num; i++) {
            sc += " ";
        }
        return sc;
    }

    

    @Override
    public boolean interceptComplete(Task<Object[], ?, Boolean> task, Boolean result) {
//        if(P.isDebug()){
//            P.d("=====发送完毕"+getClass().getSimpleName());
//        }
        endend();
        return super.interceptComplete(task, result);
    }

    @Override
    public boolean interceptCancel(Task<Object[], ?, Boolean> task) {
        if(P.isDebug()){
            P.d("=====发送取消"+getClass().getSimpleName());
        }
        endend();
        return super.interceptCancel(task);
    }

    private void endend(){
        if(isNio){

        }else
        if (sendReentrantLock != null&&sendCondition != null) {
            sendReentrantLock.lock();
            sendCondition.signalAll();
            sendReentrantLock.unlock();
        }
    }
}